﻿Imports System.Text
Imports System.Net
Imports System.IO
Imports System.Text.RegularExpressions
Imports System.Web

Public Class pageStreamer
    Public Delegate Sub dataReceivedCalledback(ByVal HTMLData As String)

#Region "Structures"
    Private Structure AsyncStateWrapper
        Public pageRequest As HttpWebRequest
        Public receivedCallback As dataReceivedCalledback
    End Structure
#End Region

#Region "Methods"
    ''' <summary>
    ''' Will stream the HTML data from a webpage asynchronously as pass it to a callback when the process has completed.
    ''' </summary>
    ''' <param name="URL">The URL of the webpage to stream.</param>
    ''' <param name="receivedCallback">The callback to return the HTML data to. HTML data will be String.Empty if an error occured.</param>
    ''' <remarks></remarks>
    Public Shared Sub StreamPage(ByVal URL As String, ByVal receivedCallback As dataReceivedCalledback)
        Dim asyncWrapper As New AsyncStateWrapper
        asyncWrapper.pageRequest = DirectCast(HttpWebRequest.Create(URL), HttpWebRequest)
        Try
            asyncWrapper.receivedCallback = receivedCallback
            asyncWrapper.pageRequest.BeginGetResponse(New AsyncCallback(AddressOf PageStreamRecieved), asyncWrapper)
        Catch ex As Exception
            asyncWrapper.receivedCallback(String.Empty)
        End Try
    End Sub
    ''' <summary>
    ''' Internal asynchronous callback for StreamPage.
    ''' </summary>
    ''' <param name="ar">The IAsyncResult from the asynchronous call.</param>
    ''' <remarks></remarks>
    Private Shared Sub PageStreamRecieved(ByVal ar As IAsyncResult)
        Dim asyncWrapper As AsyncStateWrapper = DirectCast(ar.AsyncState, AsyncStateWrapper)
        Dim pageHTMLData As String = GetResponseHTML(asyncWrapper.pageRequest.EndGetResponse(ar))
        asyncWrapper.receivedCallback(pageHTMLData)
    End Sub
    ''' <summary>
    ''' Internal function to get the HTML data from a response stream.
    ''' </summary>
    ''' <param name="pageResponse">The response to get HTML data from.</param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Private Shared Function GetResponseHTML(ByVal pageResponse As HttpWebResponse) As String
        Dim respStream As Stream = pageResponse.GetResponseStream()
        Dim respBody As String = String.Empty

        While (True)
            Dim buf As Byte() = New Byte(4092) {}
            Dim amount As Integer = respStream.Read(buf, 0, buf.Length)
            If (amount <> 0) Then
                respBody += Encoding.ASCII.GetString(buf, 0, amount)
            Else
                Exit While
            End If
        End While

        Return respBody
    End Function

    ''' <summary>
    ''' Prepares a string to be HTML compatable.
    ''' </summary>
    ''' <param name="text">The string to prepare.</param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Function Prepare(ByVal text As String) As String
        Return HttpUtility.HtmlDecode(text).Replace(Microsoft.VisualBasic.ChrW(&HA0), " "c)
    End Function
    ''' <summary>
    ''' Obtains a RegEx match in the given HTML data for the given pattern, making sure the HTML is correctly formatted.
    ''' </summary>
    ''' <param name="HTMLData">The HTML data to search through.</param>
    ''' <param name="pattern">The RegEx pattern.</param>
    ''' <returns>First group value of first match.</returns>
    ''' <remarks></remarks>
    Public Shared Function HTMLSafeMatch(ByVal HTMLData As String, ByVal pattern As String) As String
        Return Prepare(Regex.Match(HTMLData, pattern, RegexOptions.IgnoreCase Or RegexOptions.Singleline).Groups(1).Value)
    End Function
    ''' <summary>
    ''' Obtains list of RegEx matches in the given HTML data for the given pattern, making sure the HTML is correctly formatted.
    ''' </summary>
    ''' <param name="HTMLData">The HTML data to search through.</param>
    ''' <param name="pattern">The RegEx pattern.</param>
    ''' <returns>An array of strings representing the first group value of each match.</returns>
    ''' <remarks></remarks>
    Public Shared Function HTMLSafeMatches(ByVal HTMLData As String, ByVal pattern As String) As String()
        Dim matches As MatchCollection = Regex.Matches(HTMLData, pattern, RegexOptions.IgnoreCase Or RegexOptions.Singleline)
        Dim returnList As New List(Of String)
        For Each n As Match In matches
            returnList.Add(Prepare(n.Groups(1).Value))
        Next
        Return returnList.ToArray
    End Function
#End Region
End Class
